<?php
/*
 * pdo操作数据库类
 * 创建于：2016-01-11
 * 2018年完善
 * */
class dbpdo{
    //protected $_condition = array();
    protected $connection;//数据库连接标识
    protected $fetchAll;
    protected $query;
    protected $result;
    protected $num;
    protected $mode;
    protected $prepare;
    protected $row;
    protected $fetchAction;
    protected $beginTranFormAction;
    protected $rollback;
    protected $commit;
    protected $char;
    private static $get_mode;
    private static $get_fetch_action;

    private $PDOStatement = null;//PDOStatement对象  
    private static $charset = DB_CHARSET;//设置字符集
    private static $host = DB_HOST;//主机名或ip地址
    private static $DBPort = DB_PORT;//端口号
    private static $DBUser = DB_USER;//用户名
    private static $DBPass = DB_PWD;//密码
    private static $DBName = DB_NAME;//数据库名称
    private static $DBType = DB_TYPE;//数据库类型
    private static $debug = 1;//是否开启调试模式(项目上线后请关闭)
    private static $db_log = 0;//是否开启日志
    private $querySql ='';//预处理sql语句
    private $params = array();//预处理数组
    private $autoCommit = TRUE;//是否开启自动提交,不适用于查询操作,默认自动提交，如若关闭操作时请先调用方法关闭
    protected $tranFormActionCount = 0;//事务标识数
    private $db_press = DB_PREFIX;//数据库表前缀

    //构造函数
    public function __construct() {
        if (!class_exists('PDO')){
            throw new Exception('not found PDO');
            return false; 
        }
        try{
            $this->connection = new PDO(self::$DBType.':dbname='.self::$DBName.';host='.self::$host.';port='.self::$DBPort,self::$DBUser,self::$DBPass,array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES '".self::$charset."';"));
            date_default_timezone_set("PRC");
            if(self::$debug){
                error_reporting(E_ALL ^ E_NOTICE); 
            }else{
                error_reporting(NULL);
                ini_set('display_errors','Off');
            }
        }catch (PDOException $e){
            //exit($e->getMessage());
            return $this->setExceptionError($e->getMessage(), $e->getLine, $e->getFile);
        }
    }
    /**
     *
     * @param  $connection    关闭连接数据库的句柄
     */
    public function closeConnection($connection){
        try {
            if ($connection != null) {
                $this->connection = null;//关闭数据库连接句柄
            }
        }catch (Exception $e) {
            print '关闭数据库链接错误:'.$e->getMessage();
        }
    }
    /**
     *self sql get value action
    */
    public function getValueBySelfCreateSql($sql, $fetchAction = "assoc",$mode = null) {
        $this->fetchAction = $this->fetchAction($fetchAction);
        $this->result = $this->setAttribute($sql, $this->fetchAction, $mode);
        $this->AllValue = $this->result->fetchAll();
        return $this->AllValue;
    }
    /**
     *select condition can query
    */
    private function setAttribute($sql, $fetchAction= "assoc", $mode=null) {
        $this->mode = self::getMode($mode);
        $this->fetchAction = self::fetchAction($fetchAction);
        $this->connection->setAttribute(PDO::ATTR_CASE, $this->mode);
        $this->query = $this->base_query($sql);
        $this->query->setFetchMode($this->fetchAction);
        return $this->query;
    }
    /**
     *get mode action
    */
    private static function getMode($get_style){
        switch($get_style){
            case null:
                self::$get_mode = PDO::CASE_NATURAL;
            break;
            case true:
                self::$get_mode = PDO::CASE_UPPER;
            break;
            case false;
            self::$get_mode= PDO::CASE_LOWER;
            break;
        }
        return self::$get_mode;
    }
    /**
     *fetch value action
    */
    private static function fetchAction($fetchAction) {
        switch($fetchAction) {
            case "assoc":
                self::$get_fetch_action = PDO::FETCH_ASSOC; //asso array
            break;
            case "num":
                self::$get_fetch_action = PDO::FETCH_NUM; //num array
            break;
            case "object":
                self::$get_fetch_action = PDO::FETCH_OBJ; //object array
            break;
            case "both":
                self::$get_fetch_action = PDO::FETCH_BOTH; //assoc array and num array
            break;
            default:
                self::$get_fetch_action = PDO::FETCH_ASSOC;
            break;
        }
        return self::$get_fetch_action;
    }
    /**
     * 获取记录总数
     * 
    */
    public function getVal($sql){
        $this->result = $this->base_query($sql);
        $this->num = $this->result->getVal();
        return $this->num;
    }
    /*
     * 查询语句
    */
    public function query($table, $column = "*",$condition = array(), $group = "",$order = "", $having = "", $startSet = "",$endSet="",$skey = false,$fetchAction = "assoc",$params = null){
        $table=DB_PREFIX.$table;
        $sql = "select ".$column." from `".$table."` ";
        if ($condition!=null){
            if(is_array($condition)){
                foreach($condition as $key=>$value) {
                    $where .= "$key = '$value' and ";
                }
                $sql .= " where $where ";
                $sql .= " 1 = 1 ";
            }else{
                $sql.=" where $condition ";
            }
        }
        if ($group != "") {
            $sql .= " group by ".$group." ";
        }
        if ($order != "") {
            $sql .= " order by ".$order." ";
        }
        if ($having != "") {
            $sql .= " having '$having' ";//函数条件 sum('字段')>值；
        }
        //if ($startSet != "" && $endSet != "" && is_numeric($endSet) && is_numeric($startSet)) {
		if ($startSet != ""){
            $sql .= " limit $startSet,$endSet";
        }
        $this->result = $this->getValueBySelfCreateSql($sql, $fetchAction, $params);
        if($skey){//用于将数组的key用户数据表的字段替换
            foreach($this->result as $k=>$v){
                $tem[$v[$skey]]=$this->result[$k];
            }
            $this->result=$tem;
        }
        return $this->result;
    }

    /*
     * 获取单条记录
    */
    public function getOne($table, $column = "*",$condition = array(), $fetchAction = "assoc",$mode = null){
        $table=DB_PREFIX.$table;
        $sql = "select ".$column." from `".$table."` ";
        $where="";
        if ($condition!=null){
            if(is_array($condition)){
                foreach($condition as $key=>$value) {
                    $where .= "$key = '$value' and ";
                }
                $sql .= " where $where ";
                $sql .= " 1 = 1 ";
            }else{
                $sql.=" where $condition ";
            }
        }else{
            return false;
        }
        $this->fetchAction = $this->fetchAction($fetchAction);
        $this->result = $this->setAttribute($sql, $this->fetchAction, $mode);
        return $this->result->fetch();
    }
    /**
     * 执行sql语句，增、减、删、查均可以
    */
    public function exec($sql) {
        $this->result = $this->connection->exec($sql);
        $substr = substr($sql, 0 ,6);
        if ($this->result) {
            return $this->successful($substr);
        }else{
            return $this->fail($substr);
        }
    }
    /**
     *prepare action
    */
    public function prepare($sql) {
        $this->prepare = $this->connection->prepare($sql);
        $this->setChars();
        $this->prepare->execute();
        while($this->rowz = $this->prepare->fetch()) {
            return $this->row;
        }
    }
    /**
     *USE tranFormAction
    */
    public function tranFormAction($sql) {
        $this->begin();
        $this->result = $this->connection->exec($sql);
        if ($this->result) {
            $this->commit();
        } else {
            $this->rollback();
        }
    }
    /**
     *开启事务
    */
    private function begin() {
        $this->beginTranFormAction = $this->connection->beginTranFormAction();
        return $this->beginTranFormAction;
    }
    /**
     *提交事务
    */
    private function commit() {
        $this->commit = $this->connection->commit();
        return $this->commit;
    }
    /**
     *事务回滚
    */
    private function rollback() {
        $this->rollback = $this->connection->rollback();
        return $this->rollback;
    }
    /**
     *base query
    */
    private function base_query($sql) {
        $this->setChars();
        $this->query = $this->connection->query($sql);
        return $this->query;
    }
    /**
     *set chars
    */
    private function setChars() {
        $this->char = $this->connection->query("SET NAMES 'UTF8'");
        return $this->char;
    }
    /**
     *process sucessful action 
    */
    private function successful($params){
        return "The ".$params." action is successful";
    }
    /**
     *process fail action
    */
    private function fail($params){
        return "The ".$params." action is fail";
    }
    /**
     *process exception action
    */
    private function setExceptionError($getMessage, $getLine ,$getFile) {
        echo "Error message is ".$getMessage."<br /> The Error in ".$getLine." line <br /> This file dir on ".$getFile;
        exit();
    }

    /**
     * 获取插入语句
     *
     * @param    string     $table_name   表名
     * @param    array      $args       数组数据
     */
    public function insert_data($table,$args){
        $table=DB_PREFIX.$table;
		//首先判断是否为数组，再判断数组是否为空
        if(is_array($args)&&!empty($args)){
            $i = 0;
            foreach($args as $key=>$val){
                $fields[$i] = $key;	//将所有的键名放到一个$fields[]数组中
                $values[$i] = $val;	//将所有的值放到一个$values[]数组中
                $i++;
            }
            $s_fields = "(".implode(",",$fields).")";
            $s_values  = "('".implode("','",$values)."')";
            $sql = "INSERT INTO $table $s_fields VALUES $s_values";
            try {
                $this->result=$this->connection->exec($sql);
                return $this->result;
                $this->closeConnection($this->connection);//关闭数据库
            } catch (PDOException $e) {
                print 'Insert error '.$e->getMessage();
            }  
        }else{
            return false;
        }
    }

    /**
     * 还需改进。。。。获取替换语句:replace into是insert into的增强版
     * 区别：replace into跟insert功能类似，不同点在于：replace into 首先尝试插入数据到表中，如果发现表中
			 已经有此行数据(根据主键或唯一索引判断)，则先删除此行数据，然后插入新的数据，否则直接插入新数据
     * @param    string     $table      表名
     * @param    array      $args       数组数据
     */
    public function replace_data($table,$args,$fetchAction = "assoc",$mode = null){
        $table=DB_PREFIX.$table;
        if(is_array($args)&&!empty($args)){
            $i = 0;
            foreach($args as $key=>$val){
                $fields[$i] = $key;
                $values[$i] = $val;
                $i++;
            }
            $s_fields = "(".implode(",",$fields).")";
            $s_values  = "('".implode("','",$values)."')";
            $sql = "REPLACE INTO $table $s_fields VALUES $s_values";
            $this->fetchAction = $this->fetchAction($fetchAction);
            $this->result = $this->setAttribute($sql, $this->fetchAction, $mode);
            return $this->result->fetch();
        }else{
            return false;
        }
    }


    /**
     * 获取更新SQL语句
     *
     * @param    string     $table   表名
     * @param    array      $args       数据
     * @param    array      $condition  条件
     */
    public function update_data($table,$args,$condition = array()){
        $table=DB_PREFIX.$table;
        $i = 0;
        $data = '';
        if(is_array($args)&&!empty($args)){
            foreach( $args as $key=>$val ){
                if(isset($val)){
                    $val = $val;
                    if($i==0&&$val!==null){
                        $data = $key."='".$val."'";	//第一次：如，update 表名 set
                    }else{
                        $data .= ",".$key." = '".$val."'";//非第一次：如， ，password='123'
                    }
                    $i++;
                }
            }
            $sql = "UPDATE $table SET $data";
            $where="";
            if ($condition != null) {
                if(is_array($condition)){
                    foreach($condition as $key=>$value) {
                        $where .= "$key = '$value' and ";
                    }
                    $sql .= " where $where ";
                    $sql .= " 1 = 1 ";
                }else{
                    $sql.=" where $condition ";
                }
            }else{
                return false;
            }
            try {
                $this->result=$this->connection->exec($sql);
                return $this->result;
                $this->closeConnection($this->connection);//关闭数据库
            } catch (PDOException $e) {
                print 'update error '.$e->getMessage();
            }
        }else{
            Return false;
        }
    }

    /**
     * 根据条件删除数据
     * @param  string $table     表名
     * @param  array  $condition 条件 条件为空时，删除所有数据
     * @return int 返回删除总数
     */
    public function remove($table,$condition=array()){
        $table=DB_PREFIX.$table;
        $sql = "DELETE FROM $table";
        $where="";
        if ($condition != null) {
            foreach($condition as $key=>$value) {
                $where .= "$key = '$value' and ";
            }
            $sql .= " WHERE $where ";
            $sql .= " 1 = 1 ";
        }else{
            $sql.=" where $condition ";
        }
        try {
            $this->result=$this->connection->exec($sql);
            return $this->result;
            $this->closeConnection($this->connection);//关闭数据库
        } catch (PDOException $e) {
            print 'delete error '.$e->getMessage();
        }
    }

    /**
     * 取得数据库最后一个插入ID
     * @return int
     */
    public function getInsertId() {
        return $this->connection->lastInsertId();
    }

    /*
     * 获取所有数据表
     * */
    public function getDataTable() {
        $this->query = $this->base_query("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '".DB_NAME."'");
        $this->query->setFetchMode($this->fetchAction);
        return $this->query;
    }
}
?>